﻿//===================================================================
//
// Description: Sparqube Picture Column Lite for SharePoint 2010
// Web: http://www.sparqube.com/
//
//-------------------------------------------------------------------
//
// Copyright (C) 2012 ArtfulBits.CZ (development[at]artfulbits.cz)
// Web: http://www.artfulbits.cz/
//
//-------------------------------------------------------------------
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE.
//===================================================================

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace Sparqube.SharePoint.PictureColumnLite
{
	public class SimpleHtmlFieldValue
	{
		#region Internal Classes

		internal class RegExConst
		{
			internal static Regex RegexAttribValue = new Regex("(?in:(?'AttibuteNameValuePair'( )?(?'AttributeName'[^= ]*)(( )?=( )?)('(?'AttributeValue'[^']*)'|\"(?'AttributeValue'[^\"]*)\"|(?'AttributeValue'[^ ]+)?)))", RegexOptions.Compiled);
			internal static Regex RegexStyleAttribValue = new Regex("(?in:(?'AttibuteNameValuePair'( )?(?'AttributeName'[^:= ]*)(( )?[:=]( )?)(?'AttributeValue'[^;]+)?)(( )?[;]*( )?))", RegexOptions.Compiled);
		}// RegExConst

		internal class Serializer
		{
			#region Constants

			private static readonly char[] c_achNameAndValueDelimiters = new char[] { '=' };
			private static readonly char[] c_achNameValuePairDelimiters = new char[] { '&' };

			#endregion //Constants

			#region Methods

			internal static void DeserializePackedAttributeString(string packedAttributeString, ref Dictionary<string, string> packedAttributesDictionary)
			{
				if (packedAttributesDictionary == null)
				{
					packedAttributesDictionary = new Dictionary<string, string>();
				}
				if (!string.IsNullOrEmpty(packedAttributeString))
				{
					string[] strArray = packedAttributeString.Split(c_achNameValuePairDelimiters);
					int num = 0;
					foreach (string str in strArray)
					{
						num++;
						string[] strArray2 = str.Split(c_achNameAndValueDelimiters);
						if ((strArray2.Length == 2) && !string.IsNullOrEmpty(strArray2[0]))
						{
							packedAttributesDictionary[strArray2[0].ToUpperInvariant()] = HttpUtility.UrlDecode(strArray2[1]);
						}
					}
				}
			}

			public static int Int32FromString(string attributeValue)
			{
				int result = 0;
				if (!int.TryParse(attributeValue, out result))
				{
					result = 0;
				}
				return result;
			}

			public static string Int32ToString(int value, int minimumValue)
			{
				string str = string.Empty;
				if (value >= minimumValue)
				{
					str = value.ToString(CultureInfo.InvariantCulture);
				}
				return str;
			}

			internal static string SerializePackedAttributeHashTable(Dictionary<string, string> packedAttributes)
			{
				Dictionary<string, string>.Enumerator enumerator = packedAttributes.GetEnumerator();
				StringBuilder builder = new StringBuilder(string.Empty);
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, string> current = enumerator.Current;
					if (!string.IsNullOrEmpty(current.Key))
					{
						KeyValuePair<string, string> pair2 = enumerator.Current;
						string str = SPEncode.UrlEncode(pair2.Value);
						object[] args = new object[4];
						KeyValuePair<string, string> pair3 = enumerator.Current;
						args[0] = pair3.Key;
						args[1] = c_achNameAndValueDelimiters[0];
						args[2] = str;
						args[3] = c_achNameValuePairDelimiters[0];
						builder.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", args);
					}
				}
				string str2 = builder.ToString();
				if (str2 == null)
				{
					str2 = string.Empty;
				}
				return str2;
			}

			#endregion //Methods

		}// Serializer

		#endregion //Internal Classes

		#region Constants

		private static readonly string[] c_asAnchorKeyAttributes = new string[] { HtmlTextWriterAttribute.Href.ToString(), HtmlTextWriterAttribute.Target.ToString(), HtmlTextWriterAttribute.Title.ToString() };
		private static readonly string[] c_asImageKeyAttributes = new string[] { HtmlTextWriterAttribute.Align.ToString(), HtmlTextWriterAttribute.Alt.ToString(), HtmlTextWriterAttribute.Border.ToString(), HtmlTextWriterAttribute.Height.ToString(), "HSpace", HtmlTextWriterAttribute.Src.ToString(), "VSpace", HtmlTextWriterAttribute.Width.ToString(), HtmlTextWriterAttribute.Style.ToString(), HtmlTextWriterAttribute.Class.ToString() };
		private static readonly string[] c_asImageKeyAttributesV4 = new string[] { HtmlTextWriterAttribute.Align.ToString(), HtmlTextWriterAttribute.Alt.ToString(), HtmlTextWriterAttribute.Height.ToString(), HtmlTextWriterAttribute.Src.ToString(), HtmlTextWriterAttribute.Width.ToString(), HtmlTextWriterAttribute.Style.ToString(), HtmlTextWriterAttribute.Class.ToString(), HtmlTextWriterAttribute.Title.ToString() };

		private static readonly Regex c_reStyleValueOnePx = new Regex(@"(\d+)px", RegexOptions.Compiled | RegexOptions.IgnoreCase);
		private static readonly Regex c_reStyleValueTwoPx = new Regex(@"^[\s]*(\d+)px[\s]*(\d+)px", RegexOptions.Compiled | RegexOptions.IgnoreCase);

		private const string c_sKey_HtmlTagText = "HtmlTagText";

		#endregion //Constants

		#region Fields

		private Dictionary<string, string> m_packedAttributesDictionary;
		private string m_parsedAdditionalHtmlContent;
		private HtmlTextWriterTag m_tagName;

		#endregion //Fields

		#region Properties

		internal bool IsComplexTag
		{
			get
			{
				return (m_tagName != HtmlTextWriterTag.Img);
			}
		}

		internal string PackedAttributeString
		{
			get
			{
				return Serializer.SerializePackedAttributeHashTable(m_packedAttributesDictionary);
			}
			set
			{
				Serializer.DeserializePackedAttributeString(value, ref m_packedAttributesDictionary);
			}
		}

		internal HtmlTextWriterTag TagName
		{
			get
			{
				return m_tagName;
			}
		}

		private string TagNameString
		{
			get
			{
				return m_tagName.ToString().ToLowerInvariant();
			}
		}

		#endregion //Properties

		#region Indexers

		internal string this[string propertyName]
		{
			get
			{
				if (!string.IsNullOrEmpty(propertyName))
				{
					string key = propertyName.ToUpperInvariant();
					if (m_packedAttributesDictionary.ContainsKey(key))
					{
						return m_packedAttributesDictionary[key];
					}
				}
				return string.Empty;
			}
			set
			{
				if (!string.IsNullOrEmpty(propertyName))
				{
					m_packedAttributesDictionary[propertyName.ToUpperInvariant()] = value;
				}
			}
		}

		internal string this[HtmlTextWriterAttribute htmlAttribute]
		{
			get
			{
				return this[htmlAttribute.ToString()];
			}
			set
			{
				this[htmlAttribute.ToString()] = value;
			}
		}

		#endregion //Indexers

		#region Constructors

		public SimpleHtmlFieldValue()
		{
			m_packedAttributesDictionary = new Dictionary<string, string>();
			m_tagName = HtmlTextWriterTag.Span;
			m_parsedAdditionalHtmlContent = string.Empty;
		}

		internal SimpleHtmlFieldValue(HtmlTextWriterTag htmlTagName)
		{
			m_packedAttributesDictionary = new Dictionary<string, string>();
			m_tagName = HtmlTextWriterTag.Span;
			m_parsedAdditionalHtmlContent = string.Empty;
			m_tagName = htmlTagName;
		}

		internal SimpleHtmlFieldValue(string htmlString, HtmlTextWriterTag tagName) :
			this(tagName)
		{
			PopulateValuesFromPackedAttributeHtml(htmlString);
		}

		#endregion //Constructors

		#region Overrides

		public override string ToString()
		{
			return ToStringInternal(this[c_sKey_HtmlTagText]);
		}

		#endregion //Overrides

		#region Implementation

		internal virtual HtmlControl GetHtmlControl()
		{
			HtmlControl control = new HtmlGenericControl(m_tagName.ToString());
			control.Controls.Add(new LiteralControl(this[c_sKey_HtmlTagText]));
			string[] constAnchorKeyAttributes = c_asAnchorKeyAttributes;
			if (HtmlTextWriterTag.Img == m_tagName)
			{
				if ((SPContext.Current == null) || (SPContext.Current.Web.UIVersion >= 4))
				{
					constAnchorKeyAttributes = c_asImageKeyAttributesV4;
				}
				else
				{
					constAnchorKeyAttributes = c_asImageKeyAttributes;
				}
			}
			string str = HtmlTextWriterAttribute.Alt.ToString();
			foreach (string str2 in constAnchorKeyAttributes)
			{
				string str3 = this[str2.ToUpperInvariant()];
				bool flag = !string.IsNullOrEmpty(str2) && !string.IsNullOrEmpty(str3);
				bool flag2 = str.Equals(str2, StringComparison.OrdinalIgnoreCase);
				if (flag || flag2)
				{
					control.Attributes[str2] = str3;
				}
			}
			return control;
		}

		private Dictionary<string, string>.Enumerator GetEnumerator()
		{
			return m_packedAttributesDictionary.GetEnumerator();
		}

		private string GenerateHtmlAttributesString()
		{
			if (m_packedAttributesDictionary.Count == 0)
			{
				return string.Empty;
			}
			StringBuilder builder = new StringBuilder();
			string[] constAnchorKeyAttributes = c_asAnchorKeyAttributes;
			if (HtmlTextWriterTag.Img == m_tagName)
			{
				if ((SPContext.Current == null) || (SPContext.Current.Web.UIVersion >= 4))
				{
					constAnchorKeyAttributes = c_asImageKeyAttributesV4;
				}
				else
				{
					constAnchorKeyAttributes = c_asImageKeyAttributes;
				}
			}
			string str = HtmlTextWriterAttribute.Alt.ToString();
			foreach (string str2 in constAnchorKeyAttributes)
			{
				string str3 = SPEncode.HtmlEncode(this[str2.ToUpperInvariant()]);
				bool flag = !string.IsNullOrEmpty(str2) && !string.IsNullOrEmpty(str3);
				bool flag2 = str.Equals(str2, StringComparison.OrdinalIgnoreCase);
				if (flag || flag2)
				{
					builder.AppendFormat(CultureInfo.InvariantCulture, " {0}=\"{1}\"", new object[] { str2.ToLowerInvariant(), str3 });
				}
			}
			return builder.ToString();
		}

		private static bool PopulateTagValueAttributesFromHtmlAttributesString(string htmlAttributesString, SimpleHtmlFieldValue valueToPopulate)
		{
			if ((valueToPopulate == null) || string.IsNullOrEmpty(htmlAttributesString))
			{
				return false;
			}
			if (valueToPopulate.m_packedAttributesDictionary == null)
			{
				valueToPopulate.m_packedAttributesDictionary = new Dictionary<string, string>();
			}
			MatchCollection matchs = RegExConst.RegexAttribValue.Matches(htmlAttributesString);
			foreach (Match match in matchs)
			{
				string str = match.Groups["AttributeName"].Value;
				string input = SPHttpUtility.HtmlDecode(match.Groups["AttributeValue"].Value);
				if (HtmlTextWriterAttribute.Style.ToString().Equals(str, StringComparison.OrdinalIgnoreCase))
				{
					foreach (Match match2 in RegExConst.RegexStyleAttribValue.Matches(input))
					{
						string str3 = match2.Groups["AttributeName"].Value;
						string str4 = match2.Groups["AttributeValue"].Value;
						if (str3.ToUpperInvariant() == "MARGIN".ToUpperInvariant())
						{
							Match match3 = c_reStyleValueTwoPx.Match(str4);
							if (match3.Success)
							{
								valueToPopulate.m_packedAttributesDictionary["VSpace".ToUpperInvariant()] = match3.Groups[1].Value;
								valueToPopulate.m_packedAttributesDictionary["HSpace".ToUpperInvariant()] = match3.Groups[2].Value;
							}
							else
							{
								Match match4 = c_reStyleValueOnePx.Match(str4);
								if (match4.Success)
								{
									valueToPopulate.m_packedAttributesDictionary["VSpace".ToUpperInvariant()] = match4.Groups[1].Value;
									valueToPopulate.m_packedAttributesDictionary["HSpace".ToUpperInvariant()] = match4.Groups[1].Value;
								}
							}
							continue;
						}
						if (str3.ToUpperInvariant() == HtmlTextWriterAttribute.Border.ToString().ToUpperInvariant())
						{
							Match match5 = c_reStyleValueOnePx.Match(str4);
							if (!match5.Success)
							{
								continue;
							}
							valueToPopulate.m_packedAttributesDictionary[str3.ToUpperInvariant()] = match5.Groups[1].Value;
						}
					}
					continue;
				}
				if (!string.IsNullOrEmpty(str))
				{
					valueToPopulate.m_packedAttributesDictionary[str.ToUpperInvariant()] = input;
				}
			}
			return (matchs.Count > 0);
		}

		private static bool PopulateTagValueFromPackedAttributeHtml(string packedHtmlString, SimpleHtmlFieldValue valueToPopulate)
		{
			if ((valueToPopulate == null) || string.IsNullOrEmpty(packedHtmlString))
			{
				return false;
			}
			string format = @"(?in:<{0} (?'AllAttributeValues'[^>]*)>(?'HtmlContent'[\S\s]*))";
			if (valueToPopulate.IsComplexTag)
			{
				format = @"(?in:<{0} (?'AllAttributeValues'[^>]*)>(?'HtmlContent'[\S\s]*)</{0}>)";
			}
			format = string.Format(CultureInfo.InvariantCulture, format, new object[] { valueToPopulate.TagNameString });
			Match match = Regex.Match(packedHtmlString, format);
			if (match.Success)
			{
				PopulateTagValueAttributesFromHtmlAttributesString(match.Groups["AllAttributeValues"].Value, valueToPopulate);
				valueToPopulate.m_parsedAdditionalHtmlContent = match.Groups["HtmlContent"].Value;
			}
			return match.Success;
		}

		private void PopulateValuesFromPackedAttributeHtml(string packedHtmlString)
		{
			SimpleHtmlFieldValue value2;
			SimpleHtmlFieldValue value3;
			if (this.IsComplexTag)
			{
				value2 = this;
				value3 = new SimpleHtmlFieldValue(HtmlTextWriterTag.Img);
			}
			else
			{
				value2 = new SimpleHtmlFieldValue(HtmlTextWriterTag.A);
				value3 = this;
			}
			if (PopulateTagValueFromPackedAttributeHtml(packedHtmlString, value2))
			{
				if (PopulateTagValueFromPackedAttributeHtml(value2.m_parsedAdditionalHtmlContent, value3))
				{
					this[c_sKey_HtmlTagText] = value3.m_parsedAdditionalHtmlContent;
				}
				else
				{
					this[c_sKey_HtmlTagText] = value2.m_parsedAdditionalHtmlContent;
				}
			}
			else if (PopulateTagValueFromPackedAttributeHtml(packedHtmlString, value3))
			{
				this[c_sKey_HtmlTagText] = value3.m_parsedAdditionalHtmlContent;
			}
			value2[HtmlTextWriterAttribute.Src] = value3[HtmlTextWriterAttribute.Src];
			value3[HtmlTextWriterAttribute.Href] = value2[HtmlTextWriterAttribute.Href];
			value3[HtmlTextWriterAttribute.Target] = value2[HtmlTextWriterAttribute.Target];
		}

		private string ToStringInternal(string innerText)
		{
			string format = "<{0}{1}>{2}";
			if (this.IsComplexTag)
			{
				format = "<{0}{1}>{2}</{0}>";
			}
			return string.Format(CultureInfo.InvariantCulture, format, new object[] { this.TagNameString, GenerateHtmlAttributesString(), innerText });
		}

		#endregion //Implementation

	}// SimpleHtmlFieldValue
}
